home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / ipcmd.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  17KB  |  742 lines

  1. /* IP-related user commands
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4.  /* Mods by PA0GRI */
  5. #include <stdio.h>
  6. #include "global.h"
  7. #include "config.h"
  8. #include "mbuf.h"
  9. #include "internet.h"
  10. #include "timer.h"
  11. #include "netuser.h"
  12. #include "iface.h"
  13. #include "session.h"
  14. #include "ip.h"
  15. #include "cmdparse.h"
  16. #include "commands.h"
  17. #include "rip.h"
  18. #include "rspf.h"
  19. #include "domain.h"
  20. #include "pktdrvr.h"
  21. #include "socket.h"
  22.  
  23. int32 Ip_addr;
  24. #ifdef __GNUC__
  25. int Route_Sort = 1;
  26. #else
  27. extern int Route_Sort=1;
  28. #endif
  29.  
  30. static int doadd __ARGS((int argc,char *argv[],void *p));
  31. #ifdef  IPACCESS
  32. static int doaccess __ARGS((int argc,char *argv[],void *p));
  33. #endif
  34. static int dodrop __ARGS((int argc,char *argv[],void *p));
  35. static int doflush __ARGS((int argc,char *argv[],void *p));
  36. static int doipaddr __ARGS((int argc,char *argv[],void *p));
  37. static int doipstat __ARGS((int argc,char *argv[],void *p));
  38. static int dolook __ARGS((int argc,char *argv[],void *p));
  39. static int dortimer __ARGS((int argc,char *argv[],void *p));
  40. static int dottl __ARGS((int argc,char *argv[],void *p));
  41. int doipheard __ARGS((int argc,char *argv[],void *p));
  42. static int doiphport __ARGS((int argc,char *argv[],void *p));
  43. static int doiphsize __ARGS((int argc,char *argv[],void *p));
  44. void dumproute __ARGS((struct route *rp,char *p));
  45. static int doroutesort __ARGS((int argc,char *argv[],void *p));
  46.  
  47. static struct cmds Ipcmds[] = {
  48. #ifdef  IPACCESS
  49.     "access",       doaccess,       0,      0, NULLCHAR,
  50. #endif
  51.     "address",      doipaddr,       0,      0, NULLCHAR,
  52.     "heard",        doipheard,      0,      0, NULLCHAR,
  53.     "hport",        doiphport,      0,      0, NULLCHAR,
  54.     "hsize",        doiphsize,      0,      0, NULLCHAR,
  55.     "rtimer",       dortimer,       0,      0, NULLCHAR,
  56.     "status",       doipstat,       0,      0, NULLCHAR,
  57.     "ttl",          dottl,          0,      0, NULLCHAR,
  58.     NULLCHAR,
  59. };
  60. /* "route" subcommands */
  61. static struct cmds Rtcmds[] = {
  62.     "add",          doadd,          0,      3,
  63.     "route add <dest addr>[/<bits>] <if name> [<gateway> | direct [metric]]",
  64.  
  65.     "addprivate",   doadd,          0,      3,
  66.     "route addprivate <dest addr>[/<bits>] <if name> [<gateway> | direct [metric]]",
  67.  
  68.     "drop",         dodrop,         0,      2,
  69.     "route drop <dest addr>[/<bits>]",
  70.  
  71.     "flush",        doflush,        0,      0,
  72.     NULLCHAR,
  73.  
  74.     "lookup",       dolook,         0,      2,
  75.     "route lookup <dest addr>",
  76.     
  77.     "sort",         doroutesort,    0,      0,
  78.     NULLCHAR,
  79.  
  80.     NULLCHAR,
  81. };
  82.  
  83. int
  84. doip(argc,argv,p)
  85. int argc;
  86. char *argv[];
  87. void *p;
  88. {
  89.     return subcmd(Ipcmds,argc,argv,p);
  90. }
  91. #ifdef  IPACCESS
  92. static int
  93. doaccess(argc,argv,p)
  94. int argc;
  95. char *argv[];
  96. void *p;
  97. {
  98.     struct iface *ifp;
  99.     int32 source,target;
  100.     unsigned sbits,tbits;
  101.     char *bitp;
  102.     int16 lport,hport,protocol,state;
  103.     char *cp; /* for printing the table */
  104.     struct rtaccess *tpacc;
  105.     struct rtaccess *btacc;
  106.     struct rtaccess *bfacc;
  107.     struct rtaccess *head;
  108.     char tmpbuf[15];
  109.  
  110.     if(argc == 1){ /* print out the table */
  111.         tprintf("Source Address  Len Dest Address    Len Interface    Proto Low   High  State\n");
  112.         for(tpacc = IPaccess;tpacc != NULLACCESS;tpacc = tpacc->nxtiface){
  113.             for(btacc = tpacc;btacc != NULLACCESS;btacc = btacc->nxtbits){
  114.                 if(btacc->source != 0)
  115.                     cp = inet_ntoa(btacc->source);
  116.                 else
  117.                     cp = "all";
  118.                 tprintf("%-16s",cp);
  119.                 tprintf("%2u  ",btacc->sbits);
  120.                 if(btacc->target != 0)
  121.                     cp = inet_ntoa(btacc->target);
  122.                 else
  123.                     cp = "all";
  124.                 tprintf("%-16s",cp);
  125.                 tprintf("%2u  ",btacc->bits);
  126.                 tprintf("%-13s",btacc->iface->name);
  127.                 switch (btacc->protocol) {
  128.                     case 0:
  129.                         cp = "any";
  130.                         break;
  131.                     case ICMP_PTCL:
  132.                         cp = "icmp";
  133.                         break;
  134.                     case TCP_PTCL:
  135.                         cp = "tcp";
  136.                         break;
  137.                     case UDP_PTCL:
  138.                         cp = "udp";
  139.                         break;
  140.                     default:
  141.                         cp = itoa(btacc->protocol,tmpbuf,10);
  142.                 }
  143.                 tprintf("%-5s ",cp);
  144.                 tprintf("%5u ",btacc->lowport);
  145.                 tprintf("%5u ",btacc->highport);
  146.                 if(btacc->status)
  147.                     cp = "deny";
  148.                 else
  149.                     cp = "permit";
  150.                 tprintf("%-6s\n",cp);
  151.             }
  152.         }
  153.         return 0;
  154.     }
  155.  
  156.     if(strcmp(argv[1],"permit") == 0){
  157.         state = 0;
  158.     } else {
  159.         if((strcmp(argv[1],"deny") == 0) 
  160.         || (strcmp(argv[1],"delete") == 0)){
  161.             state = -1;
  162.         } else {
  163.             tprintf(" Format: ip access <permit|deny|delete> <proto> <src addr>[/<bits>] <dest addr>[/<bits>] <if name> [low [high]]\n");
  164.             return 1;
  165.         }
  166.     }
  167.  
  168.     switch (*argv[2]){
  169.         case 'a':       /* ANY */
  170.             protocol = 0;
  171.             break;
  172.         case 'i':       /* ICMP */
  173.             protocol = ICMP_PTCL;
  174.             break;
  175.         case 't':       /* TCP */
  176.             protocol = TCP_PTCL;
  177.             break;
  178.         case 'u':       /* UDP */
  179.             protocol = UDP_PTCL;
  180.             break;
  181.         default:
  182.             protocol = atoi(argv[2]);
  183.     }
  184.  
  185.     if(strcmp(argv[3],"all") == 0){
  186.         source = 0;
  187.         sbits = 0;
  188.     } else {
  189.         /* If IP address is followed by an optional slash and
  190.          * a length field, (e.g., 128.96/16) get it;
  191.          * otherwise assume a full 32-bit address
  192.          */
  193.         if((bitp = strchr(argv[3],'/')) != NULLCHAR){
  194.             /* Terminate address token for resolve() call */
  195.             *bitp++ = '\0';
  196.             sbits = atoi(bitp);
  197.         } else
  198.             sbits = 32;
  199.  
  200.         if((source = resolve(argv[3])) == 0){
  201.             tprintf(Badhost,argv[3]);
  202.             return 1;
  203.         }
  204.     }
  205.     if(strcmp(argv[4],"all") == 0){
  206.         target = 0;
  207.         tbits = 0;
  208.     } else {
  209.         if((bitp = strchr(argv[4],'/')) != NULLCHAR){
  210.             *bitp++ = '\0';
  211.             tbits = atoi(bitp);
  212.         } else
  213.             tbits = 32;
  214.  
  215.         if((target = resolve(argv[4])) == 0){
  216.             tprintf(Badhost,argv[4]);
  217.             return 1;
  218.         }
  219.     }
  220.     
  221.     if((ifp = if_lookup(argv[5])) == NULLIF){
  222.     tprintf(Badinterface,argv[5]);
  223.         return 1;
  224.     }
  225.  
  226.     if(((protocol != TCP_PTCL) && (protocol != UDP_PTCL)) || (argc < 7)) {
  227.         lport = 0;
  228.         hport = 0;
  229.     } else {
  230.         if(strcmp(argv[6],"all") == 0){
  231.             lport = 0;
  232.         } else {
  233.             lport = atoi(argv[6]);
  234.         }
  235.         if((argc < 8) || (lport == 0))
  236.             hport = lport;
  237.         else
  238.             hport = atoi(argv[7]);
  239.     }
  240.  
  241.     if(strcmp(argv[1],"delete") == 0){
  242.         head = IPaccess;
  243.         for(tpacc = IPaccess;tpacc != NULLACCESS;head = tpacc,tpacc = tpacc->nxtiface){
  244.             if(tpacc->iface == ifp){
  245.                 for(btacc = tpacc;btacc != NULLACCESS;
  246.                      head = btacc,btacc = btacc->nxtbits){
  247.                     if((btacc->protocol == protocol) &&
  248.                        (btacc->source == source)     &&
  249.                        (btacc->sbits == sbits)       &&
  250.                        (btacc->target == target)     &&
  251.                        (btacc->bits == tbits)        &&
  252.                        (btacc->lowport == lport)     &&
  253.                        (btacc->highport == hport)) { /*match*/
  254.                         bfacc = btacc; /* save to unalloc */
  255.                 /*now delete. watch for special cases*/
  256.                         if(btacc != tpacc){ /* not at head of list */
  257.                          head->nxtbits = btacc->nxtbits;
  258.                             free(bfacc);
  259.                             return 0;
  260.                         }
  261.                         if(btacc == IPaccess){ /* real special case */
  262.                         if(IPaccess->nxtbits == NULLACCESS)
  263.                             IPaccess = btacc->nxtiface;
  264.                         else {
  265.                             IPaccess = btacc->nxtbits;
  266.                             (btacc->nxtbits)->nxtiface = btacc->nxtiface;
  267.                         }
  268.                         } else { /* we know tpacc=btacc <> IPaccess */
  269.                         if(btacc->nxtbits == NULLACCESS)
  270.                             head->nxtiface = btacc->nxtiface;
  271.                         else {
  272.                             head->nxtiface = btacc->nxtbits;
  273.                             (btacc->nxtbits)->nxtiface = btacc->nxtiface;
  274.                         }
  275.                         }
  276.                     free(bfacc);
  277.                     return 0;
  278.                     }
  279.                 }
  280.             }
  281.         }
  282.         tprintf("Not found.\n");
  283.         return 1;
  284.     }
  285.     /* add the access */
  286.     addaccess(protocol,source,sbits,target,tbits,ifp,lport,hport,state);
  287.     return 0;
  288. }
  289. #endif
  290. static int
  291. doipaddr(argc,argv,p)
  292. int argc;
  293. char *argv[];
  294. void *p;
  295. {
  296.     int32 n;
  297.  
  298.     if(argc < 2) {
  299.         tprintf("%s\n",inet_ntoa(Ip_addr));
  300.     } else if((n = resolve(argv[1])) == 0){
  301.         tprintf(Badhost,argv[1]);
  302.         return 1;
  303.     } else
  304.         Ip_addr = n;
  305.     return 0;
  306. }
  307. static int
  308. dortimer(argc,argv,p)
  309. int argc;
  310. char *argv[];
  311. void *p;
  312. {
  313.     return setlong(&ipReasmTimeout,"IP reasm timeout (sec)",argc,argv);
  314. }
  315. static int
  316. dottl(argc,argv,p)
  317. int argc;
  318. char *argv[];
  319. void *p;
  320. {
  321.     return setlong(&ipDefaultTTL,"IP Time-to-live",argc,argv);
  322. }
  323.  
  324.  
  325. char RouteHeader[] = "Destination      Len Interface Gateway          Metric P Timer  Use\n";
  326.  
  327. /* Display and/or manipulate routing table */
  328. int
  329. doroute(argc,argv,p)
  330. int argc;
  331. char *argv[];
  332. void *p;
  333. {
  334.     register int i,j,k,bits,flow_tmp;
  335.     register struct route *rp;
  336.     char *temp,temp2[80];
  337.  
  338.     if(argc >= 2)
  339.         return subcmd(Rtcmds,argc,argv,p);
  340.  
  341.     /* Dump IP routing table
  342.      * Dest            Len Interface    Gateway          Use
  343.      * 192.001.002.003 32  sl0          192.002.003.004  0
  344.      * modified for Sorted output - D. Crompton 2.92
  345.      */
  346.       
  347.     flow_tmp=Current->flowmode;
  348.     Current->flowmode=1;
  349.     
  350.     tputs(RouteHeader);
  351.  
  352.     for(j=0,bits=31;bits>=0;bits--)
  353.        for(i=0;i<HASHMOD;i++)
  354.           for(rp = Routes[bits][i];rp != NULLROUTE;j++,rp = rp->next);
  355.  
  356.     if (j){
  357.     
  358.       temp=mallocw((unsigned)j*80);
  359.  
  360.       for(bits=31,k=0;bits>=0;bits--)
  361.         for(i=0;i<HASHMOD;i++)
  362.             for(rp = Routes[bits][i];rp != NULLROUTE;rp = rp->next,k+=80)
  363.                 dumproute(rp,&temp[k]);
  364.       
  365.       if (Route_Sort) qsort(temp,(size_t)j,80,(int (*)__FARGS((const void*,const void*))) strcmp);
  366.     
  367.       for (i=0,k=4;i<j;i++,k+=80) {
  368.           tprintf("%s",&temp[k]);
  369.           if (tprintf("\n") == EOF)
  370.              {
  371.               Current->flowmode=flow_tmp;
  372.               free(temp);
  373.               return 0;
  374.              }
  375.       }
  376.      free(temp);
  377.     }
  378.     if(R_default.iface != NULLIF){
  379.         dumproute(&R_default,temp2);
  380.     tprintf("%s\n",&temp2[4]);
  381.      }
  382.     Current->flowmode = flow_tmp;
  383.     return 0;
  384. }
  385.  
  386. /* Dump a routing table entry */
  387. void
  388. dumproute(rp,temp)
  389. register struct route *rp;
  390. char *temp;
  391. {
  392.     char *cp;
  393.     unsigned int a=0;
  394.     char *name;                      
  395.  
  396.     if(rp->target != 0) {
  397.     if(DTranslate && (name = resolve_a(rp->target,!DVerbose)) != NULLCHAR) {
  398.         strcpy(temp,name);
  399.         free(name);
  400.         } else {    
  401.         cp = inet_ntobos(rp->target);
  402.         sprintf(temp,"%4s",cp);
  403.         }
  404.         cp = inet_ntoa(rp->target);
  405.     } else {
  406.     strcpy(temp,"default");    /* Don't really matter, but avoid unknown value */
  407.     cp = "default";
  408.     }
  409.     a=4;
  410.     a+=sprintf(&temp[a],"%-16.16s ",cp);
  411.     a+=sprintf(&temp[a],"%-4u",rp->bits);
  412.     a+=sprintf(&temp[a],"%-9.9s ",rp->iface->name);
  413.     if(rp->gateway != 0)
  414.         cp = inet_ntoa(rp->gateway);
  415.     else
  416.         cp = "";
  417.     a+=sprintf(&temp[a],"%-16.16s ",cp);
  418.     a+=sprintf(&temp[a],"%-6lu ",rp->metric);
  419.     a+=sprintf(&temp[a],"%c ",(rp->flags & RTPRIVATE) ? 'P' : ' ');
  420.     if(rp->timer.state == TIMER_STOP){
  421.         if(rp->timer.duration == 1) a+=sprintf(&temp[a],"rspf   ");
  422.         else a+=sprintf(&temp[a],"man    ");
  423.     } else {
  424.         a+=sprintf(&temp[a],"%-7lu",read_timer(&rp->timer) / 1000L);
  425.     }
  426.     sprintf(&temp[a],"%lu",rp->uses);
  427. }
  428.  
  429.  
  430. /* Sort Route dump */
  431. static int
  432. doroutesort(argc,argv,p)
  433. int argc ;
  434. char *argv[] ;
  435. void *p;
  436. {
  437.     extern int Route_Sort;
  438.  
  439.     return setbool(&Route_Sort,"Route Sort flag",argc,argv);
  440. }
  441.  
  442.  
  443. /* Add an entry to the routing table
  444.  * E.g., "add 1.2.3.4 ax0 5.6.7.8 3"
  445.  */
  446. static int
  447. doadd(argc,argv,p)
  448. int argc;
  449. char *argv[];
  450. void *p;
  451. {
  452.     struct iface *ifp;
  453.     int32 dest,gateway;
  454.     unsigned bits;
  455.     char *bitp;
  456.     int32 metric;
  457.     char private;
  458.  
  459.     if(strncmp(argv[0],"addp",4) == 0)
  460.         private = 1;
  461.     else
  462.         private = 0;
  463.     if(strcmp(argv[1],"default") == 0){
  464.         dest = 0L;
  465.         bits = 0;
  466.     } else {
  467.         /* If IP address is followed by an optional slash and
  468.          * a length field, (e.g., 128.96/16) get it;
  469.          * otherwise assume a full 32-bit address
  470.          */
  471.         if((bitp = strchr(argv[1],'/')) != NULLCHAR){
  472.             /* Terminate address token for resolve() call */
  473.             *bitp++ = '\0';
  474.             bits = atoi(bitp);
  475.         } else
  476.             bits = 32;
  477.  
  478.         if((dest = resolve(argv[1])) == 0){
  479.             tprintf(Badhost,argv[1]);
  480.             return 1;
  481.         }
  482.     }
  483.     if((ifp = if_lookup(argv[2])) == NULLIF){
  484.     tprintf(Badinterface,argv[2]);
  485.         return 1;
  486.     }
  487.  
  488.     metric = 1;
  489.  
  490.     if(argc > 3){
  491.         /* Next "trick is needed to set the metric on subnets
  492.          * higher as the default 1 for rspf.
  493.          * route add subnet/bits iface default 10  
  494.          */
  495.         if(strcmp(argv[3],"direct") == 0){      /* N1BEE */
  496.             gateway = 0;
  497.         /* calculate a nice metric based on subnet mask size */
  498.             if(bits != 0 && bits < 32)
  499.                 metric = (39 - bits) * 5 / 17;
  500.         } else {
  501.             if((gateway = resolve(argv[3])) == 0){
  502.                 tprintf(Badhost,argv[3]);
  503.                 return 1;
  504.             }
  505.         }
  506.     } else {
  507.         gateway = 0;
  508.     }
  509.     if (argc > 4)
  510.         metric = atol(argv[4]);
  511.  
  512.     if(rt_add(dest,bits,gateway,ifp,metric,0,private) == NULLROUTE)
  513.         tprintf("Can't add route\n");
  514. #ifdef  RSPF
  515.     if(!private)
  516.         rspfrouteupcall(dest,bits,gateway);     /* Do an RSPF upcall */
  517. #endif  /* RSPF */
  518.     return 0;
  519. }
  520. /* Drop an entry from the routing table
  521.  * E.g., "drop 128.96/16
  522.  */
  523. static int
  524. dodrop(argc,argv,p)
  525. int argc;
  526. char *argv[];
  527. void *p;
  528. {
  529.     char *bitp;
  530.     unsigned bits;
  531.     int32 n;
  532.  
  533.     if(strcmp(argv[1],"default") == 0){
  534.         n = 0L;
  535.         bits = 0;
  536.     } else {
  537.         /* If IP address is followed by an optional slash and length field,
  538.          * (e.g., 128.96/16) get it; otherwise assume a full 32-bit address
  539.          */
  540.         if((bitp = strchr(argv[1],'/')) != NULLCHAR){
  541.             /* Terminate address token for resolve() call */
  542.             *bitp++ = '\0';
  543.             bits = atoi(bitp);
  544.         } else
  545.             bits = 32;
  546.  
  547.         if((n = resolve(argv[1])) == 0){
  548.             tprintf(Badhost,argv[1]);
  549.             return 1;
  550.         }
  551.     }
  552.     return rt_drop(n,bits);
  553. }
  554. /* Force a timeout on all temporary routes */
  555. static int
  556. doflush(argc,argv,p)
  557. int argc;
  558. char *argv[];
  559. void *p;
  560. {
  561.     register struct route *rp;
  562.     struct route *rptmp;
  563.     int i,j;
  564.     
  565.     if(R_default.timer.state == TIMER_RUN){
  566.         rt_drop(0,0);   /* Drop default route */
  567.     }
  568.     for(i=0;i<HASHMOD;i++){
  569.         for(j=0;j<32;j++){
  570.             for(rp = Routes[j][i];rp != NULLROUTE;rp = rptmp){
  571.                 rptmp = rp->next;
  572.                 if(rp->timer.state == TIMER_RUN){
  573.                     rt_drop(rp->target,rp->bits);
  574.                 }
  575.             }
  576.         }
  577.     }
  578.     return 0;
  579. }
  580.  
  581. static int
  582. dolook(argc,argv,p)
  583. int argc;
  584. char *argv[];
  585. void *p;
  586. {
  587.     struct route *rp;
  588.     int32 addr;
  589.     char temp[80];
  590.  
  591.     addr = resolve(argv[1]);
  592.     if(addr == 0){
  593.     tprintf(Badhost,argv[1]);
  594.         return 1;
  595.     }
  596.     if((rp = rt_lookup(addr)) == NULLROUTE){
  597.         tprintf("Host %s (%s) unreachable\n",argv[1],inet_ntoa(addr));
  598.         return 1;
  599.     }
  600.     
  601.     dumproute(rp,temp);
  602.     tputs(RouteHeader);
  603.     tprintf("%s\n",&temp[4]);
  604.     
  605.     return 0;
  606. }
  607.  
  608. static int
  609. doipstat(argc,argv,p)
  610. int argc;
  611. char *argv[];
  612. void *p;
  613. {
  614.     register struct reasm *rp;
  615.     register struct frag *fp;
  616.     int i;
  617.  
  618.     for(i=1;i<=NUMIPMIB;i++){
  619.         tprintf("(%2u)%-20s%10lu",i,
  620.          Ip_mib[i].name,Ip_mib[i].value.integer);
  621.         if(i % 2)
  622.             tprintf("     ");
  623.         else
  624.             tprintf("\n");
  625.     }
  626.     if((i % 2) == 0)
  627.         tprintf("\n");
  628.  
  629.     if(Reasmq != NULLREASM)
  630.         tprintf("Reassembly fragments:\n");
  631.     for(rp = Reasmq;rp != NULLREASM;rp = rp->next){
  632.         tprintf("src %s",inet_ntoa(rp->source));
  633.         tprintf(" dest %s",inet_ntoa(rp->dest));
  634.         if(tprintf(" id %u pctl %u time %lu len %u\n",
  635.          rp->id,uchar(rp->protocol),read_timer(&rp->timer),
  636.          rp->length) == EOF)
  637.             break;
  638.         for(fp = rp->fraglist;fp != NULLFRAG;fp = fp->next){
  639.             if(tprintf(" offset %u last %u\n",fp->offset,
  640.             fp->last) == EOF)
  641.                 break;
  642.         }
  643.     }
  644.     return 0;
  645. }
  646.  
  647. /* IP heard logging - WG7J */
  648. static struct iph *iph_create __ARGS((int32 addr));
  649. static struct iph *iph_lookup __ARGS((int32 addr));
  650. struct iph *Iph;
  651.  
  652. static int Maxipheard = MAXIPHEARD;
  653.  
  654. static int doiphsize(int argc,char *argv[],void *p) {
  655.     return setint(&Maxipheard,"Max ip-heard",argc,argv);
  656. }
  657.  
  658. /* Configure a port to do ip-heard logging */
  659. static int
  660. doiphport(argc,argv,p)
  661. int argc;
  662. char *argv[];
  663. void *p;
  664. {
  665.     return setflag(argc,argv[1],LOG_IPHEARD,argv[2]);
  666. }
  667.  
  668. int
  669. doipheard(int argc,char *argv[],void *p) {
  670.     struct iph *iph;
  671.  
  672.     if(tputs("Tcp/Ip systems heard:\n"
  673.          "Address                Port       Since       Pkts\n") == EOF)
  674.     return EOF;
  675.     for(iph=Iph;iph;iph=iph->next) {
  676.     if(tprintf("%-22s %-8s %12s %5ld\n",inet_ntoa(iph->addr),iph->iface->name,
  677.         tformat(secclock() - iph->time),iph->count) == EOF)
  678.         return EOF;
  679.     }
  680.     return 0;
  681. }
  682.  
  683. void
  684. log_ipheard(int32 addr,struct iface *ifp) {
  685.     struct iph *niph;
  686.  
  687.     if((niph = iph_lookup(addr)) == NULLIPH)
  688.     if((niph = iph_create(addr)) == NULLIPH)
  689.             return;
  690.     niph->iface = ifp;
  691.     niph->count++;
  692.     niph->time = secclock();
  693. }
  694.  
  695. /* Look up an entry in the ip data base */
  696. struct iph *
  697. iph_lookup(addr)
  698. int32 addr;
  699. {
  700.     register struct iph *ip;
  701.     struct iph *last = NULLIPH;
  702.  
  703.     for(ip = Iph;ip != NULLIPH;last = ip,ip = ip->next){
  704.     if(ip->addr == addr) {
  705.         if(last != NULLIPH){
  706.                 /* Move entry to top of list */
  707.         last->next = ip->next;
  708.         ip->next = Iph;
  709.         Iph = ip;
  710.             }
  711.         return ip;
  712.         }
  713.     }
  714.     return NULLIPH;
  715. }
  716.  
  717. /* Create a new entry in the source database */
  718. /* If there are too many entries, override the oldest one - WG7J */
  719. static struct iph *
  720. iph_create(addr)
  721. int32 addr;
  722. {
  723.     static int numdb;
  724.     register struct iph *iph;
  725.     struct iph *last = NULLIPH;
  726.  
  727.     if(Maxipheard && numdb == Maxipheard) {
  728.     /* find and use last one in list */
  729.     for(iph = Iph;iph->next != NULLIPH;last = iph,iph = iph->next);
  730.     /* delete entry from end */
  731.     last->next = NULLIPH;
  732.     } else {    /* create a new entry */
  733.     numdb++;
  734.     iph = (struct iph *)callocw(1,sizeof(struct iph));
  735.     }
  736.     iph->addr = addr;
  737.     iph->next = Iph;
  738.     Iph = iph;
  739.  
  740.     return iph;
  741. }
  742.